package memorydata;

import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.TreeMap;
import java.util.Vector;

import csvreader.CSVParser;

import data.Data;
import data.LUN;
import data.LUNPerTimeUnit;
import data.TimeUnit;
import data.GeneralDefinitions.ClusteringPriorityParameters;
import data.GeneralDefinitions.OrderingParameters;

public class MemoryData implements Data {

	Vector<LUN> luns;
	Vector<TimeUnit> timeUnits;
	Vector<LUNPerTimeUnit> lptus;
	private String filename;

	public MemoryData() {
		luns = new Vector<LUN>();
		timeUnits = new Vector<TimeUnit>();
		lptus = new Vector<LUNPerTimeUnit>();

	}

	@Override
	public void addLun(int lun_id, int size) {
		luns.add(new LUN(lun_id, size));
	}

	@Override
	public void addLunPerTimeUnit(int lun_id, int timeunit_id,
			double kbWritten, double kbRead, double numOfReads,
			double numOfWrites) {
		lptus.add(new LUNPerTimeUnit(this, lun_id, timeunit_id, kbWritten, kbRead, numOfReads, numOfWrites));

	}

	@Override
	public void addTimeUnit(int timeUnit_id, int size) {
		timeUnits.add(new TimeUnit(timeUnit_id, size));

	}

	@Override
	public void endTransactions() {
		for (LUNPerTimeUnit lptu: lptus){
			LUN l = lptu.get_lun();
			TimeUnit t = lptu.get_timeUnit();
			l.updateWithLPTU(lptu);
			t.updateWithLPTU(lptu);
		}
	}

	@Override
	public LUNPerTimeUnit[] getAllLunPerTimeUnits(int timeUnitId, int start, int end, final OrderingParameters orderingParameter) {
//		System.out.println("MemoryData, getAllLunPerTimeUnits: Started working");
		Vector<LUNPerTimeUnit> tmp = new Vector<LUNPerTimeUnit>();
		for (LUNPerTimeUnit lptu: lptus){
			if (lptu.get_timeUnit().get_id()==timeUnitId){
				tmp.add(lptu);
			}
		}
		Collections.sort(tmp, new Comparator<LUNPerTimeUnit>(){
			@Override
			public int compare(LUNPerTimeUnit o1, LUNPerTimeUnit o2) {
				if (o1.getField(orderingParameter) > o2.getField(orderingParameter)) return -1;
				else if (o1.getField(orderingParameter) < o2.getField(orderingParameter)) return 11;
				return 0;
			}
			//TODO check that the order is right (what should it be? ascending or descending??)
		});
		LUNPerTimeUnit[] res = new LUNPerTimeUnit[end-start+1];
		for (int i=start; i<=end; i++){
			res[i-start] = tmp.get(i);
		}
//		System.out.println("MemoryData, getAllLunPerTimeUnits: Finished working");
		return res;
	}

	@Override
	public LUN getLUN(int LUNid) {
		for (LUN l: luns){
			if (l.get_id() == LUNid){
				return l;
			}
		}
		return null;
	}

	@Override
	public LUNPerTimeUnit getLUNPerTimeUnit(int TimeUnitID, int LUNid) {
		for (LUNPerTimeUnit lptu: lptus){
			if (lptu.get_lun().get_id() == LUNid && lptu.get_timeUnit().get_id() == TimeUnitID){
				return lptu;
			}
		}
		return null;
	}

	@Override
	public double[] getLUNVector(int LUNid,	ClusteringPriorityParameters clusterType, Calendar startDate,
			Calendar endDate) {

		Vector<Double> ans = new Vector<Double>();
		//get all the time units participating

		Vector<LUNPerTimeUnit> temp = new Vector<LUNPerTimeUnit>();
		Vector<TimeUnit> temp2 = new Vector<TimeUnit>();
		TreeMap<TimeUnit, Double> tempmap= new TreeMap<TimeUnit, Double>();

		//get all participating time units

		for (TimeUnit t: timeUnits){
			//TODO!!!!! how to do this?!?!?
//			if (t.get_startTime().after(startDate) &&
//					t.get_endTime().before(endDate)){
				temp2.add(t);
//			}
		}

		//get all corresponding lptu's for the data
		for (LUNPerTimeUnit lptu: lptus){
			if (lptu.get_lun().get_id() == LUNid){
				tempmap.put(lptu.get_timeUnit(), lptu.getField(clusterType));
				temp.add(lptu);
			}
		}

		//TODO check that the order is right (what should it be? ascending or descending??)
//		Collections.sort(temp, new Comparator<LUNPerTimeUnit>(){
//			@Override
//			public int compare(LUNPerTimeUnit lptu1, LUNPerTimeUnit lptu2) {
//				TimeUnit t1 = lptu1.get_timeUnit();
//				TimeUnit t2 = lptu2.get_timeUnit();
//				if (t1.get_id()>t2.get_id()) return -1;
//				else if (t1.get_id()<t2.get_id()) return 1;
//				return 0;
//			}
//		});
		Collections.sort(temp2, new Comparator<TimeUnit>(){
			@Override
			public int compare(TimeUnit t1, TimeUnit t2) {
				if (t1.get_id()>t2.get_id()) return -1;
				else if (t1.get_id()<t2.get_id()) return 1;
				return 0;
			}
		});

		//get the correct value for each time unit
		for (TimeUnit t: temp2){
			Double value = tempmap.get(t);
			if (t == null){
				ans.add(0.0);
			} else {
				ans.add(value);
			}
		}
		return convert(ans);
	}

	@Override
	public int[] getLUNs() {
		int[] ans = new int[luns.size()];
		int index = 0;
		for (LUN l: luns){
			ans[index] = l.get_id();
			index++;
		}
		return ans;
	}

	@Override
	public int getNumOfTimeUnits() {
		return timeUnits.size();
	}


	//TODO WHY IS THERE NO TIME UNIT ID HERE ?
	//TODO this query sorts the LunPerTimeUnits, and just picks one of them randomly because of the DISTINCT(see SQLiteDB), i believe it is very wrong
	//TODO therefore it only uses the LUNs and not LUNPerTimeUnit
	@Override
	public int[] getOrderedLUNVector(final OrderingParameters orderingParameter) {
		int[] ans = new int[luns.size()];
		//TODO check that the order is in the right direction
		//TODO consider start and end

		Collections.sort(luns, new Comparator<LUN>(){
			@Override
			public int compare(LUN o1, LUN o2) {
				if (o1.getField(orderingParameter) > o2.getField(orderingParameter)) return -1;
				else if (o1.getField(orderingParameter) < o2.getField(orderingParameter)) return -1;
				return 0;
			}
		});

		int index = 0;
		for (LUN l: luns){
			ans[index] = l.get_id();
			index++;
		}
		return ans;
	}

	@Override
	public TimeUnit getTimeUnit(int TimeUnitID) {
		for (TimeUnit t: timeUnits){
			if (t.get_id()==TimeUnitID){
				return t;
			}
		}
		return null;
	}

	@Override
	public long getTotalBytesWritten(int TimeUnitID) {
		TimeUnit t = getTimeUnit(TimeUnitID);
		return t.get_totalKbWritten();
	}

	@Override
	public double getTotalSize() {
		int size = 0;
		for (LUN l: luns){
			size+= l.get_size();
		}
		return size;
	}


	//TODO isnt the totalKBRead should be "=" threshhold and not "<" (see the function in SQLiteDB.java too)
	@Override
	public int[] getUnactiveLUNs(int threshold) {
		Vector<Integer> ans = new Vector<Integer>();
		for (LUN l:luns){
			if (l.get_totalKbRead() < threshold){
				ans.add(l.get_id());
			}
		}
		return convert(ans);
	}

	@Override
	public void parse(String filename) {
		this.filename = filename;
		new CSVParser().parseFile(filename, this);
	}

	private double[] convert(Vector<Double> vec) {
		double[] ans = new double[vec.size()];
		for (int i = 0; i < vec.size(); i++) {
			ans[i] = vec.get(i);
		}
		return ans;
	}


	private int[] convert(Vector<Integer> vec) {
		int[] ans = new int[vec.size()];
		for (int i = 0; i < vec.size(); i++) {
			ans[i] = vec.get(i);
		}
		return ans;
	}
	
	@Override
	public String getFIleName() {
		return filename;
	}

	@Override
	public void addTimeUnit(int timeUnit_id, int size, Calendar d) {
		// TODO Auto-generated method stub
		
	}
}
